package com.zyb.beiojbackendjudgeservice.service.impl;

import cn.hutool.json.JSONUtil;

import com.zyb.beiojbackendjudgeservice.codesandbox.CodeSandbox;
import com.zyb.beiojbackendjudgeservice.codesandbox.CodeSandboxFactory;
import com.zyb.beiojbackendjudgeservice.codesandbox.CodeSandboxProxy;
import com.zyb.beiojbackendjudgeservice.service.JudgeService;
import com.zyb.beiojbackendjudgeservice.strategy.StrategyContext;
import com.zyb.beiojbackendjudgeservice.strategy.StrategyManager;
import com.zyb.beiojbackendserviceclient.service.QuestionFeignClient;
import com.zyb.beiojbackendserviceclient.service.UserFeignClient;
import com.zyb.beiojcommon.common.ErrorCode;
import com.zyb.beiojcommon.exception.BusinessException;
import com.zyb.beiojmodel.model.codesandbox.ExecuteCodeRequest;
import com.zyb.beiojmodel.model.codesandbox.ExecuteCodeResponse;
import com.zyb.beiojmodel.model.codesandbox.QuestionJudgeInfo;
import com.zyb.beiojmodel.model.dto.question.QuestionJudgeCase;
import com.zyb.beiojmodel.model.entity.Question;
import com.zyb.beiojmodel.model.entity.QuestionSubmit;
import com.zyb.beiojmodel.model.entity.User;
import com.zyb.beiojmodel.model.enums.CodeSandboxTypeEnum;
import com.zyb.beiojmodel.model.enums.QuestionSubmitStatusEnum;
import com.zyb.beiojmodel.model.vo.QuestionSubmitVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 十八岁讨厌编程
 * @date 2025/2/10 22:24
 * @PROJECT_NAME beioj-backend
 * @description  判题服务实现类
 */

@Service
public class JudgeServiceImpl implements JudgeService {


    @Resource
    private QuestionFeignClient questionService;

    @Value("${codesandbox.type:example}")
    private String type;

    @Resource
    private StrategyManager strategyManager;

    @Resource
    private CodeSandboxFactory codeSandboxFactory;


    @Override
    public QuestionSubmit doJudge(Long questionSubmitId, Long userId) {

        //判题服务业务流程：
        //● 根据传入的提交id得到对应的题目、提交信息（代码、status、judgeInfo）
        QuestionSubmit questionSubmit = questionService.getQuestionSubmitById(questionSubmitId);
        String language = questionSubmit.getLanguage();
        String code = questionSubmit.getCode();
        Integer status = questionSubmit.getStatus();
        Long questionId = questionSubmit.getQuestionId();
        //● 如果题目提交状态不为等待中（status = WAITING）就不重复执行(注意：status不可能为空，所以无需进行判断是否为空)
        if (!QuestionSubmitStatusEnum.WAITING.equals(QuestionSubmitStatusEnum.getEnumByValue(status))) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR,"不要重复提交判题申请");
        }
        //● 否则就执行。更改题目提交状态为“判题中”（status = RUNNING）。这样防止重复执行，也能让用户即使看到状态
        questionSubmit.setStatus(QuestionSubmitStatusEnum.RUNNING.getValue());
        questionService.updateQuestionSubmitById(questionSubmit);
        //● 调用沙箱，获取到执行结果
        CodeSandbox codeSandbox = codeSandboxFactory.selectCodeSandbox(CodeSandboxTypeEnum.getEnumByValue(type));
        CodeSandboxProxy codeSandboxProxy = new CodeSandboxProxy(codeSandbox);
        Question question = questionService.getQuestionById(questionId);
        List<QuestionJudgeCase> questionJudgeCaseList = JSONUtil.toList(question.getJudgeCase(), QuestionJudgeCase.class);
        List<String> collect = questionJudgeCaseList.stream().map(questionJudgeCase -> {
            return questionJudgeCase.getInput().toString();
        }).collect(Collectors.toList());
        ExecuteCodeRequest executeCodeRequest = ExecuteCodeRequest.builder()
                .code(code)
                .inputList(collect)
                .language(language)
                .userId(userId)
                .build();
        ExecuteCodeResponse executeCodeResponse = codeSandboxProxy.executeCode(executeCodeRequest);

        //组装策略环境，执行策略
        StrategyContext strategyContext = new StrategyContext();
        strategyContext.setExecuteCodeResponse(executeCodeResponse);
        strategyContext.setQuestionJudgeCaseList(questionJudgeCaseList);
        strategyContext.setQuestion(question);
        strategyContext.setQuestionSubmit(questionSubmit);
        QuestionJudgeInfo doneJudge = strategyManager.doJudge(strategyContext);

        //修改题目提交状态以及判题信息
        questionSubmit.setStatus(QuestionSubmitStatusEnum.SUCCESS.getValue());
        questionSubmit.setJudgeInfo(JSONUtil.toJsonStr(doneJudge));
        boolean b = questionService.updateQuestionSubmitById(questionSubmit);
        if (!b) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR,"题目提交记录更新失败");
        }


        //最后重新查询返回提交vo
        QuestionSubmit questionSubmitResult = questionService.getQuestionSubmitById(questionSubmitId);

        return questionSubmitResult;

    }
}
